package com.tgit.sso.paltform.central.controller;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;
import java.util.stream.Collectors;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import com.tgit.sso.core.common.ResponseT;
import com.tgit.sso.paltform.central.entity.*;
import com.tgit.sso.paltform.config.ConfigInfo;
import com.tgit.sso.paltform.util.ExecutorTaskUtil;
import com.tgit.sso.paltform.util.LoginUtil;
import com.tgit.sso.paltform.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.apache.commons.lang3.StringUtils;
import com.tgit.sso.core.conf.SsoConf;
import com.tgit.sso.core.conf.SsoException;
import com.tgit.sso.core.conf.SsoUser;
import com.tgit.sso.core.util.CookieUtil;
import com.tgit.sso.core.util.EncryptUtil;
import com.tgit.sso.core.util.JedisUtil;
import com.tgit.sso.core.util.SsoLoginHandlerUtils;
import com.tgit.sso.paltform.central.service.UserService;
import com.google.code.kaptcha.impl.DefaultKaptcha;

/**
 * web端控制
 * @author 范再军
 * 2018年10月8日
 */
@Controller
public class WebController {
	
	@Autowired
	UserService userService;
	@Autowired
	DefaultKaptcha captchaProducer;

    @RequestMapping("/")
    public String index(Model model, HttpServletRequest request) {

        //是否登录校验
        SsoUser ssoUser = SsoLoginHandlerUtils.loginCheck(request);
        
        //进行登录控制
        if (ssoUser == null) {
            return "redirect:/login";
        } else {
            //判断是否有默认跳转地址
            if(!StringUtils.isBlank(ConfigInfo.DEFAULT_URL)) {
                return "redirect:" + ConfigInfo.DEFAULT_URL;
            }

            return "success";
        }
    }

    /**
     * 进入登录页面
     * /login
     * @param model
     * @param request
     * @return
     */
    @RequestMapping(SsoConf.SSO_LOGIN)
    public String login(Model model, HttpServletRequest request,Map<String,Object> map) {
        //sso登录用户
    	SsoUser ssoUser = SsoLoginHandlerUtils.loginCheck(request);
    	//ssoUser
    	if (ssoUser != null) {
            //登录成功重定向
            String redirectUrl = request.getParameter(SsoConf.REDIRECT_URL);
            if (StringUtils.isNotBlank(redirectUrl)) {
                String sessionId = SsoLoginHandlerUtils.getSessionIdByCookie(request);
                String redirectUrlFinal = redirectUrl + "?" + SsoConf.SSO_SESSIONID + "=" + sessionId;
                return "redirect:" + redirectUrlFinal;
            } else {
                return "redirect:/";
            }
        }

    	//注册和忘记密码url跳转
    	map.put("casUrl", ConfigInfo.CAS_URL);
    	map.put("userCenterUrl", "");
    	//版权、公司信息
        map.put("copyright", LoginUtil.getCopyright());
        //是否国际化
        map.put("languageFlag", ConfigInfo.LANGUAGE_FLAG);
        //公告
        Boolean noticeFlag = LoginUtil.getNoticeFlag();
        map.put("noticeFlag", noticeFlag);
        if(noticeFlag) {
            map.put("noticeContent", LoginUtil.getNoticeContent());
        }
        map.put("ERRORCODE",request.getParameter("errorCode"));
        //校验REDIRECT_URL的合法性
        String redirectUrl=request.getParameter(SsoConf.REDIRECT_URL);
        List<Product> products=userService.findProcutInfo(null);
        if(!StringUtils.isEmpty(redirectUrl)) {
            model.addAttribute(SsoConf.REDIRECT_URL, request.getParameter(SsoConf.REDIRECT_URL));
            if(SsoConf.validUrl(redirectUrl)) {
                //获取合适的登录信息
                products.stream().forEach(product -> {
                    if(LoginUtil.checkUrlDomain(redirectUrl,product)){
                        map.put("product",product);
                    }
                });
        	}
        }
        if(map.get("product")==null){
            Product defaultSso=products.stream().filter(product -> product.getId().equals("1")).collect(Collectors.toList()).get(0);
            map.put("product",defaultSso);
        }
        return "login";
    }


    /**
     * 进入注册页面
     * /login
     * @param model
     * @param request
     * @return
     */
    @RequestMapping(SsoConf.RE_USER)
    public String reuser(Model model, HttpServletRequest request,Map<String,Object> map) {
        String service=request.getParameter(SsoConf.SERVICE);
        map.put("service",service==null?"":service);
        //注册和忘记密码url跳转
        map.put("casUrl", ConfigInfo.CAS_URL);
        map.put("userCenterUrl", "");
        //版权、公司信息
        map.put("copyright", LoginUtil.getCopyright());
        //是否国际化
        map.put("languageFlag", ConfigInfo.LANGUAGE_FLAG);
        //公告
        Boolean noticeFlag = LoginUtil.getNoticeFlag();
        map.put("noticeFlag", noticeFlag);
        if(noticeFlag) {
            map.put("noticeContent", LoginUtil.getNoticeContent());
        }
        map.put("ERRORCODE",request.getParameter("errorCode"));
        //校验REDIRECT_URL的合法性
        String redirectUrl=request.getParameter(SsoConf.REDIRECT_URL);
        List<Product> products=userService.findProcutInfo(null);
        if(!StringUtils.isEmpty(redirectUrl)) {
            model.addAttribute(SsoConf.REDIRECT_URL, request.getParameter(SsoConf.REDIRECT_URL));
            if(SsoConf.validUrl(redirectUrl)) {
                //获取合适的登录信息
                products.stream().forEach(product -> {
                    if(LoginUtil.checkUrlDomain(redirectUrl,product)){
                        map.put("product",product);
                    }
                });
            }
        }
        if(map.get("product")==null){
            Product defaultSso=products.stream().filter(product -> product.getId().equals("1")).collect(Collectors.toList()).get(0);
            map.put("product",defaultSso);
        }
        return "reuser";
    }


    /**
     * 进入修改密码页面
     * /login
     * @param model
     * @param request
     * @return
     */
    @RequestMapping(SsoConf.RE_PWD)
    public String repwd(Model model, HttpServletRequest request,Map<String,Object> map) {
        String service=request.getParameter(SsoConf.SERVICE);
        map.put("service",service==null?"":service);
        //注册和忘记密码url跳转
        map.put("casUrl", ConfigInfo.CAS_URL);
        map.put("userCenterUrl", "");
        //版权、公司信息
        map.put("copyright", LoginUtil.getCopyright());
        //是否国际化
        map.put("languageFlag", ConfigInfo.LANGUAGE_FLAG);
        //公告
        Boolean noticeFlag = LoginUtil.getNoticeFlag();
        map.put("noticeFlag", noticeFlag);
        if(noticeFlag) {
            map.put("noticeContent", LoginUtil.getNoticeContent());
        }
        map.put("ERRORCODE",request.getParameter("errorCode"));
        //校验REDIRECT_URL的合法性
        String redirectUrl=request.getParameter(SsoConf.REDIRECT_URL);
        List<Product> products=userService.findProcutInfo(null);
        if(!StringUtils.isEmpty(redirectUrl)) {
            model.addAttribute(SsoConf.REDIRECT_URL, request.getParameter(SsoConf.REDIRECT_URL));
            if(SsoConf.validUrl(redirectUrl)) {
                //获取合适的登录信息
                products.stream().forEach(product -> {
                    if(LoginUtil.checkUrlDomain(redirectUrl,product)){
                        map.put("product",product);
                    }
                });
            }
        }
        if(map.get("product")==null){
            Product defaultSso=products.stream().filter(product -> product.getId().equals("1")).collect(Collectors.toList()).get(0);
            map.put("product",defaultSso);
        }
        return "resetpwd";
    }

    /**
     * 进入修改密码页面
     * /login
     * @param model
     * @param request
     * @return
     */
    @RequestMapping(SsoConf.RE_AGREEMENT)
    public String agreement(Model model, HttpServletRequest request,Map<String,Object> map) {

        //注册和忘记密码url跳转
        map.put("casUrl", ConfigInfo.CAS_URL);
        map.put("userCenterUrl", "");
        //版权、公司信息
        map.put("copyright", LoginUtil.getCopyright());
        //是否国际化
        map.put("languageFlag", ConfigInfo.LANGUAGE_FLAG);
        //公告
        Boolean noticeFlag = LoginUtil.getNoticeFlag();
        map.put("noticeFlag", noticeFlag);
        if(noticeFlag) {
            map.put("noticeContent", LoginUtil.getNoticeContent());
        }
        map.put("ERRORCODE",request.getParameter("errorCode"));
        //校验REDIRECT_URL的合法性
        String redirectUrl=request.getParameter(SsoConf.REDIRECT_URL);
        List<Product> products=userService.findProcutInfo(null);
        if(!StringUtils.isEmpty(redirectUrl)) {
            model.addAttribute(SsoConf.REDIRECT_URL, request.getParameter(SsoConf.REDIRECT_URL));
            if(SsoConf.validUrl(redirectUrl)) {
                //获取合适的登录信息
                products.stream().forEach(product -> {
                    if(LoginUtil.checkUrlDomain(redirectUrl,product)){
                        map.put("product",product);
                    }
                });
            }
        }
        if(map.get("product")==null){
            Product defaultSso=products.stream().filter(product -> product.getId().equals("1")).collect(Collectors.toList()).get(0);
            map.put("product",defaultSso);
        }
        return "agreement";
    }


    /**
     * 执行登录操作
     * @param request
     * @param response
     * @param redirectAttributes
     * @return
     */
    @PostMapping(SsoConf.SSO_DO_LOGIN)
    public String doLogin(HttpServletRequest request,
                        HttpServletResponse response,
                        RedirectAttributes redirectAttributes) {

        String errorCode = null;
        String username=request.getParameter("username");
        String password=request.getParameter("password");
        String validCode=request.getParameter("validCode");
        //校验用户信息
        AccountInfo accountInfo = null;
        try {
        	/***************************用户名和密码,验证码初步验证***********************************************/
            LoginUtil.isBlank(username, password, validCode);
            accountInfo = userService.findByUsername(username);
            if (accountInfo == null) {
                throw new SsoException(SsoConf.ERRORCODE.USERNAME_PASSWORD.name());
            }
            /*******************************************验证码校验*****************************************/
            String validCodeCache=JedisUtil.getStringValue(request.getSession().getId());
            //通过||短路原则判断
            if(validCodeCache==null) throw new SsoException(SsoConf.ERRORCODE.VALID_CODE_ERROR.name());
            /*******************************************密码校验*****************************************/
            String dbPassword=accountInfo.getPassword();
            String comparePwdCommon="";
            String comparePwdWhite="";
            //加密模式(前端用一个(md5+sha256),秘钥为验证码
            try {
                //sha256-模型支持,数据库入库之前已经做了EncryptUtil.hmacSha256(dbPassword,"tgit")入库
                //EncryptUtil.hmacSha256(dbPassword,"tgit") ;
                comparePwdCommon =  EncryptUtil.hmacSha256(dbPassword,validCode) ;
                comparePwdWhite = EncryptUtil.hmacSha256(EncryptUtil.hmacSha256(dbPassword,"tgit"),validCode);
			} catch (Exception e) {
				throw new SsoException(SsoConf.ERRORCODE.USERNAME_PASSWORD.name());
			}
            //白名单控制-密文登录
			if(ConfigInfo.WHITE_LIST !=null && ConfigInfo.WHITE_LIST.contains(SsoConf.getRequestIp(request))) {
                //不匹配抛出异常
			    if (!password.equals(comparePwdWhite) && !password.equals(comparePwdCommon)) {
			    	throw new SsoException(SsoConf.ERRORCODE.USERNAME_PASSWORD.name());
                }
			}else {
				//不匹配抛出异常
				if (!password.equals(comparePwdCommon)) {
					throw new SsoException(SsoConf.ERRORCODE.USERNAME_PASSWORD.name());
                }
				//匹配继续往下执行
			}
        } catch (SsoException e) {
        	errorCode = e.getMessage();
        }

        if (StringUtils.isNotBlank(errorCode)) {
            redirectAttributes.addAttribute("errorCode", errorCode);
            redirectAttributes.addAttribute(SsoConf.REDIRECT_URL, request.getParameter(SsoConf.REDIRECT_URL));
            return "redirect:/login";
        }
        
        //登录成功，插入redis
        SsoUser ssoUser = new SsoUser();
        ssoUser.setUserid(accountInfo.getUserId());
        ssoUser.setUsername(accountInfo.getUserName());
        Locale locale = (Locale)request.getSession().getAttribute("i18n_language_session");
        String ssoLocale = Locale.US.equals(locale) ? "en_US" : "zh_CN";
        
        //会话sessionId
        String sessionId = UUID.randomUUID().toString();
        
        //获取当前req里的sessionId值,从redis清除掉，为啥要清除，请联系作者qq：1299578272
        String reqSessionId=CookieUtil.getValue(request, SsoConf.SSO_SESSIONID);
        if(reqSessionId!=null && JedisUtil.exists(reqSessionId)) {
        	JedisUtil.expire(reqSessionId, 0);
        }
        //插入到redis
        SsoLoginHandlerUtils.login(response, sessionId, ssoUser, ssoLocale);

        //登录成功重定向地址
        String redirectUrl = request.getParameter(SsoConf.REDIRECT_URL);
        //redirectUrl校验
        if (StringUtils.isNotBlank(redirectUrl)) {
            String redirectUrlFinal = redirectUrl + "?" + SsoConf.SSO_SESSIONID + "=" + sessionId;
            return "redirect:" + redirectUrlFinal;
        } else {
        	//判断是否有默认跳转地址
        	if(!StringUtils.isBlank(ConfigInfo.DEFAULT_URL)) {
        		String redirectUrlFinal = ConfigInfo.DEFAULT_URL + "?" + SsoConf.SSO_SESSIONID + "=" + sessionId;
        		return "redirect:" + redirectUrlFinal;
        	}
        	//没有默认跳转
            return "redirect:/";
        }
    }


    /**
     * @Description: 用户注册
     * @param req -入参
     * @return
     * @author fanzj@tgit.com
     * @date 2019/11/25 18:35
     */
    @PostMapping(SsoConf.DO_RE_USER)
    @ResponseBody
    public ResponseT<String> doReUser(@Valid @RequestBody ReqUserRegister req, HttpServletRequest request) {
        String validCodeRedisId = request.getSession().getId()+"##";
        Integer userExists = userService.findUserExists(req.getEmail(),req.getUserName());
        if(userExists!=null && userExists.intValue()>0) return new ResponseT<>(500,"邮箱或用户名已绑定");
        //验证码校验
        if(validCodeRedisId !=null && JedisUtil.getStringValue(validCodeRedisId).equals(req.getValidCode())){
            userService.registerUserInfo(req);
            return ResponseT.SUCCESS;
        }
        return new ResponseT<>(500,"邮箱验证码错误");
    }
    /**
     * @Description: 邮箱验证码-有效期5分钟
     * @param req -入参
     * @return
     * @author fanzj@tgit.com
     * @date 2019/11/25 18:35
     */
    @PostMapping(SsoConf.DO_SEND_EMAIL)
    @ResponseBody
    public ResponseT<String> doSendEmail(@Valid @RequestBody ReqSendEmail req,HttpServletRequest request) {
        //用户校验
        Integer userExists = userService.findUserExists(req.getEmail(),req.getUserName());
        if(req.getType().equals(1)) {
            if (userExists != null && userExists.intValue() > 0) return new ResponseT<>(500, "该邮箱或账号已被绑定");
        }
        if(req.getType().equals(2)) {
            if (userExists == null || userExists.intValue() == 0) return new ResponseT<>(500, "该邮箱或账号未被使用");
        }
        //放入到redis共享-集群和分布式可用性
        String capText = captchaProducer.createText();
        JedisUtil.setStringValue(request.getSession().getId()+"##", capText.toUpperCase(),60*5);
        ExecutorTaskUtil.sendEmail(req.getEmail(),capText.toUpperCase());
        return ResponseT.SUCCESS;
    }
    /**
     * @Description: 用户注册
     * @param req -入参
     * @return
     * @author fanzj@tgit.com
     * @date 2019/11/25 18:35
     */
    @PostMapping(SsoConf.DO_RE_PWD)
    @ResponseBody
    public ResponseT<String> doRePwd(@Valid @RequestBody ReqUserPwd req,HttpServletRequest request) {
        //用户校验
        Integer userExists = userService.findUserExists(req.getEmail(),req.getUserName());
        if (userExists == null || userExists.intValue() == 0) return new ResponseT<>(500, "该邮箱或账号未被使用");
        //验证码校验
        if(!req.getValidCode().equals(JedisUtil.getStringValue(request.getSession().getId()+"##"))) return new ResponseT<>(500, "该邮箱或账号未被使用");
        //修改密码
        String pwd= StringUtil.genPwd();
        try {
            String pwd2=EncryptUtil.hmacSha256(EncryptUtil.getMd5Str(pwd),"tgit");
            userService.updateUserPwd(req,pwd2);
            ExecutorTaskUtil.sendEmail(req.getEmail(),pwd);
        } catch (Exception e) {
            e.printStackTrace();
            return  new ResponseT<>(500,"加密失败");
        }
        return new ResponseT<>(null);
    }

    /**
     * 登出
     * /logout
     * @param request
     * @param redirectAttributes
     * @return 重定向地址/login,再由login调转到对应的客户端地址
     */
    @RequestMapping(SsoConf.SSO_LOGOUT)
    public String logout(HttpServletRequest request, HttpServletResponse response, RedirectAttributes redirectAttributes) {
        //登出操作
        SsoLoginHandlerUtils.logout(request, response);
        //重定向属性配置
        redirectAttributes.addAttribute(SsoConf.REDIRECT_URL, request.getParameter(SsoConf.REDIRECT_URL));
        return "redirect:/login";
    }

    
    @RequestMapping(value = "/getValidCodeImage")
    public ModelAndView getKaptchaImage(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        response.setDateHeader("Expires", 0);
        response.setHeader("Cache-Control",
                "no-store, no-cache, must-revalidate");
        response.addHeader("Cache-Control", "post-check=0, pre-check=0");
        response.setHeader("Pragma", "no-cache");
        response.setContentType("image/jpeg");
        String capText = captchaProducer.createText();
        try {
            JedisUtil.setStringValue(request.getSession().getId(), capText.toUpperCase(),60*5);
        } catch (Exception e) {
            e.printStackTrace();
        }
        BufferedImage bi = captchaProducer.createImage(capText);
        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(bi, "jpg", out);
        try {
            out.flush();
        } finally {
            out.close();
        }
        return null;
    }

}
